﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace DecodeInterface
{
    public abstract class DecodeIntPtr : IDecode<IntPtr, Bitmap>
    {
        Stopwatch watch = new Stopwatch();

        DecodeExplorer decodeExplorer = null;

        private void CheckInOut(IntPtr imageIn)
        {
            if (imageIn == IntPtr.Zero)
                throw new ApplicationException("input image is null!|Decode");
        }
        private Size CheckState(object[] state)
        {
            if (state == null)
                throw new ArgumentException("state is null|Decode");
            if (state.Length != 2 || !(state[0] is int) || !(state[1] is int))
                throw new ArgumentException("state must be width and height|Decode");

            return new Size((int)state[0], (int)state[1]);
        }

        #region IDecode<IntPtr,Bitmap> 成员

        Bitmap decodeImage;
        public Bitmap DecodeImage
        {
            get
            {
                if (decodeImage != null)
                {
                    lock (decodeImage)
                    {
                        return decodeImage.Clone() as Bitmap;
                    }
                }
                else
                    return null;
            }
        }

        public Control DecodeShow
        {
            get
            {
                if (decodeExplorer == null) return null;
                else return decodeExplorer.DecodeShow;
            }
            set
            {
                if (decodeExplorer == null)
                {
                    if (value != null)
                        this.decodeExplorer = new DecodeExplorer(value);
                }
                else
                {
                    this.decodeExplorer.DecodeShow = value;
                }
            }
        }

        public long ElapsedMilliseconds
        {
            get { return watch.ElapsedMilliseconds; }
        }

        public object[] Decode(IntPtr imageIn, params object[] state)
        {
            CheckInOut(imageIn);
            Size sizeOut = CheckState(state);
            if (this.decodeImage == null)
                this.decodeImage = new Bitmap(sizeOut.Width, sizeOut.Height);
            Bitmap imageOut = this.decodeImage;

            object[] result = new object[0];
            watch.Reset();
            watch.Start();
            lock (imageOut)
            {
                Rectangle rectOut = new Rectangle(0, 0, sizeOut.Width, sizeOut.Height);
                BitmapData dataOut = imageOut.LockBits(rectOut, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                unsafe
                {
                    byte* pIn = (byte*)imageIn;
                    byte* pOut = (byte*)(dataOut.Scan0.ToPointer());
                    result = OnDecode(pIn, pOut, imageOut.Size, imageOut.Size, state);
                }
                imageOut.UnlockBits(dataOut);
            }

            if (this.decodeExplorer != null)
                this.decodeExplorer.InputImage(this.DecodeImage);

            watch.Stop();

            return result;
        }

        public void ShowImage()
        {
            if (this.decodeExplorer != null)
                this.decodeExplorer.ShowImage();
        }

        #endregion

        unsafe protected abstract object[] OnDecode(byte* pIn, byte* pOut, Size sizeIn, Size sizeOut, params object[] state);
    }
}
